package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"jlpay-sdk-go/pkg/jlpay/core"
	"jlpay-sdk-go/pkg/jlpay/models"
	"jlpay-sdk-go/pkg/jlpay/services"
	"jlpay-sdk-go/pkg/jlpay/utils"
)

// SM2密钥常量
const (
	// PEM格式密钥（与Python版本保持一致）
	sm2PrivateKey = `-----BEGIN EC PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgHqOp471SMDsQml2G
2ErpZPLD2X7rbMqa6P1O9Zqlhe+gCgYIKoEcz1UBgi2hRANCAAQkmEWaN4xGn0bB
KHG1a6e/pafL/+YODalye7SWUNC8hijk7dH5qXf016RyJnQEitPbVj9AmteAkijI
GvpJOaXq
-----END EC PRIVATE KEY-----`

	sm2PublicKey = `-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEJJhFmjeMRp9GwShxtWunv6Wny//m
Dg2pcnu0llDQvIYo5O3R+al39NekciZ0BIrT21Y/QJrXgJIoyBr6STml6g==
-----END PUBLIC KEY-----`

	jlpayPublicKey = `-----BEGIN PUBLIC KEY-----
MIIBMzCB7AYHKoZIzj0CATCB4AIBATAsBgcqhkjOPQEBAiEA/////v//////////
//////////8AAAAA//////////8wRAQg/////v////////////////////8AAAAA
//////////wEICjp+p6dn140TVqeS89lCafzl4n1FauPkt28vUFNlA6TBEEEMsSu
LB8ZgRlfmQRGajnJlI/jC7/yZgvhcVpFiTNMdMe8Nzai9PZ3nFm9zuNraSFT0KmH
fMYqR0AC3zLlITnwoAIhAP////7///////////////9yA99rIcYFK1O79Ak51UEj
AgEBA0IABKZ3VWwH0Aw9xvOWXb+xM2gXyApWEAZLFy8UyIigp3ehOTwPJ693njrg
NavTLdzAtFBqXRreivlwBTIFy8iRgn8=
-----END PUBLIC KEY-----`
)

func main() {
	// 启用调试模式
	enableDebugMode()

	// 创建配置 - 使用Builder模式
	config := core.NewConfig().
		WithAppID("1vzougr30f9vcw").
		WithBaseURL("https://upload-uat.jlpay.com").
		WithPrivateKey(sm2PrivateKey).
		WithJlpayPublicKey(jlpayPublicKey).
		WithConnectTimeout(30 * time.Second).
		WithReadTimeout(60 * time.Second).
		Build()

	// 打印配置信息
	printConfig(config)

	// 打印签名调试信息
	printSignatureDebugInfo()

	// 确保sample_files目录存在
	createSampleFilesDir()

	// 创建文件服务
	fileService := services.NewFileService(config)

	fmt.Println("=" + strings.Repeat("=", 48))
	fmt.Println("===== 商户文件上传示例 开始 =====")
	fmt.Println("=" + strings.Repeat("=", 48))

	// 示例1: 上传图片
	fmt.Println("\n=== 图片上传示例 ===")
	if err := uploadImageExample(fileService); err != nil {
		log.Printf("图片上传失败: %v", err)
		printDebugInfo("图片上传", err)
	}

	// 示例2: 上传视频
	fmt.Println("\n=== 视频上传示例 ===")
	if err := uploadVideoExample(fileService); err != nil {
		log.Printf("视频上传失败: %v", err)
		printDebugInfo("视频上传", err)
	}

	// 示例3: 上传PDF
	fmt.Println("\n=== PDF上传示例 ===")
	if err := uploadPdfExample(fileService); err != nil {
		log.Printf("PDF上传失败: %v", err)
		printDebugInfo("PDF上传", err)
	}

	fmt.Println("\n=" + strings.Repeat("=", 48))
	fmt.Println("===== 所有示例执行完毕 =====")
	fmt.Println("=" + strings.Repeat("=", 48))
}

// enableDebugMode 启用调试模式
func enableDebugMode() {
	// 设置日志级别为DEBUG
	log.SetFlags(log.LstdFlags | log.Lshortfile)
	fmt.Println("🔧 调试模式已启用")

	// 设置SDK日志级别为debug
	utils.SetLogLevel("debug")
	fmt.Println("🔧 SDK日志级别设置为DEBUG")
}

// printConfig 打印配置信息
func printConfig(config *core.Config) {
	fmt.Println("\n📋 配置信息:")
	fmt.Printf("  BaseURL: %s\n", config.BaseURL)
	fmt.Printf("  AppID: %s\n", config.AppID)
	fmt.Printf("  ConnectTimeout: %v\n", config.ConnectTimeout)
	fmt.Printf("  ReadTimeout: %v\n", config.ReadTimeout)
	fmt.Printf("  私钥长度: %d 字符 (PEM格式)\n", len(config.PrivateKey))
	fmt.Printf("  公钥长度: %d 字符 (PEM格式)\n", len(config.JlpayPublicKey))
}

// printDebugInfo 打印调试信息
func printDebugInfo(operation string, err error) {
	fmt.Printf("\n🔍 %s 调试信息:\n", operation)
	fmt.Printf("  错误类型: %T\n", err)
	fmt.Printf("  错误信息: %v\n", err)

	// 如果有额外的调试信息，可以在这里添加
	fmt.Println("  建议检查项:")
	fmt.Println("    1. 网络连接是否正常")
	fmt.Println("    2. 私钥格式是否正确")
	fmt.Println("    3. AppID是否有效")
	fmt.Println("    4. 文件是否存在且格式正确")
}

// printRequestInfo 打印请求信息（如果SDK支持）
func printRequestInfo(request interface{}) {
	fmt.Println("\n📤 请求信息:")

	// 尝试将请求序列化为JSON以便查看
	if data, err := json.MarshalIndent(request, "  ", "  "); err == nil {
		fmt.Printf("  请求体: %s\n", string(data))
	} else {
		fmt.Printf("  请求对象: %+v\n", request)
	}
}

// createSampleFilesDir 检查示例文件目录
func createSampleFilesDir() {
	// 检查examples/sample_files目录是否存在
	sampleDir := filepath.Join("examples", "sample_files")
	if _, err := os.Stat(sampleDir); os.IsNotExist(err) {
		err := os.MkdirAll(sampleDir, 0755)
		if err != nil {
			log.Printf("创建示例文件目录失败: %v", err)
		} else {
			fmt.Printf("创建了示例文件目录: %s\n", sampleDir)
			fmt.Println("请在此目录中放置测试用的图片、视频和PDF文件")
		}
	}
}

// checkFileExists 检查文件是否存在
func checkFileExists(filePath string) error {
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		return fmt.Errorf("文件不存在: %s", filePath)
	}
	return nil
}

// getExampleFilePath 获取示例文件路径，优先使用examples/sample_files目录中的文件
func getExampleFilePath(filename string) (string, error) {
	// 检查多个可能的路径，优先使用examples/sample_files
	possiblePaths := []string{
		filepath.Join("examples", "sample_files", filename), // 优先使用examples/sample_files
		filepath.Join("..", "sample_files", filename),
		filepath.Join("sample_files", filename),
		filename, // 当前目录
	}

	for _, path := range possiblePaths {
		if err := checkFileExists(path); err == nil {
			return path, nil
		}
	}

	// 如果都不存在，返回建议的路径和错误信息
	return possiblePaths[0], fmt.Errorf("测试文件不存在。请将您的测试文件放置在以下位置之一:\n1. %s (推荐)\n2. %s\n3. %s\n4. %s\n或修改代码中的filePath变量为您的实际文件路径",
		possiblePaths[0], possiblePaths[1], possiblePaths[2], possiblePaths[3])
}

// printFileInfo 打印文件信息
func printFileInfo(filePath string) {
	if fileInfo, err := os.Stat(filePath); err == nil {
		fmt.Printf("📁 文件信息:\n")
		fmt.Printf("  文件名: %s\n", fileInfo.Name())
		fmt.Printf("  文件大小: %d bytes (%.2f KB)\n", fileInfo.Size(), float64(fileInfo.Size())/1024)
		fmt.Printf("  修改时间: %s\n", fileInfo.ModTime().Format("2006-01-02 15:04:05"))
		fmt.Printf("  文件扩展名: %s\n", filepath.Ext(filePath))
	} else {
		fmt.Printf("❌ 无法获取文件信息: %v\n", err)
	}
}

// printResponseInfo 打印响应信息
func printResponseInfo(operation string, response *models.FileUploadResponse) {
	fmt.Printf("\n🔍 %s 响应信息:\n", operation)
	fmt.Printf("  响应状态: %v\n", response.IsSuccess())
	if response.GetRetCode() != "" {
		fmt.Printf("  返回码: %s\n", response.GetRetCode())
	}
	if response.GetRetMsg() != "" {
		fmt.Printf("  返回消息: %s\n", response.GetRetMsg())
	}
	if response.GetFileURL() != "" {
		fmt.Printf("  文件URL: %s\n", response.GetFileURL())
	}
	if response.GetMediaID() != "" {
		fmt.Printf("  媒体ID: %s\n", response.GetMediaID())
	}
}

// uploadImageExample 图片上传示例
func uploadImageExample(fileService *services.FileService) error {
	// 获取示例图片文件路径 - 使用与Python版本相同的文件名
	filePath, err := getExampleFilePath("test_image.png")
	if err != nil {
		fmt.Printf("提示: %v\n", err)
		fmt.Println("支持的图片格式: .jpg, .jpeg, .png, .gif, .bmp")
		return nil // 不返回错误，只是提示
	}

	fmt.Printf("使用图片文件: %s\n", filePath)

	// 打印文件信息
	printFileInfo(filePath)

	// 创建图片上传请求
	request := &models.ImageUploadRequest{}

	// 设置文件路径
	fmt.Println("🔧 正在设置文件路径...")
	if err := request.SetFileFromPath(filePath); err != nil {
		return fmt.Errorf("设置文件路径失败: %w", err)
	}

	// 打印请求信息
	printRequestInfo(request)

	// 发送上传请求
	fmt.Println("📤 正在发送上传请求...")
	response, err := fileService.UploadImage(request)
	if err != nil {
		fmt.Printf("❌ 请求发送失败: %v\n", err)
		return fmt.Errorf("上传图片失败: %w", err)
	}

	// 打印响应信息
	printResponseInfo("图片上传", response)

	// 处理响应
	if response.IsSuccess() {
		fmt.Printf("✅ 图片上传成功！\n")
		if response.GetFileURL() != "" {
			fmt.Printf("  文件URL: %s\n", response.GetFileURL())
		}
		if response.GetMediaID() != "" {
			fmt.Printf("  媒体ID: %s\n", response.GetMediaID())
		}
	} else {
		fmt.Printf("❌ 图片上传失败: %s - %s\n", response.GetRetCode(), response.GetRetMsg())
	}

	return nil
}

// uploadVideoExample 视频上传示例
func uploadVideoExample(fileService *services.FileService) error {
	// 获取示例视频文件路径
	filePath, err := getExampleFilePath("test_video.mp4")
	if err != nil {
		fmt.Printf("提示: %v\n", err)
		fmt.Println("支持的视频格式: .mp4, .avi, .mov, .wmv, .flv")
		return nil // 不返回错误，只是提示
	}

	fmt.Printf("使用视频文件: %s\n", filePath)

	// 打印文件信息
	printFileInfo(filePath)

	// 创建视频上传请求
	request := &models.VideoUploadRequest{}

	// 设置文件路径
	fmt.Println("🔧 正在设置文件路径...")
	if err := request.SetFileFromPath(filePath); err != nil {
		return fmt.Errorf("设置文件路径失败: %w", err)
	}

	// 打印请求信息
	printRequestInfo(request)

	// 发送上传请求
	fmt.Println("📤 正在发送上传请求...")
	response, err := fileService.UploadVideo(request)
	if err != nil {
		fmt.Printf("❌ 请求发送失败: %v\n", err)
		return fmt.Errorf("上传视频失败: %w", err)
	}

	// 打印响应信息
	printResponseInfo("视频上传", response)

	// 处理响应
	if response.IsSuccess() {
		fmt.Printf("✅ 视频上传成功！\n")
		if response.GetFileURL() != "" {
			fmt.Printf("  文件URL: %s\n", response.GetFileURL())
		}
		if response.GetMediaID() != "" {
			fmt.Printf("  媒体ID: %s\n", response.GetMediaID())
		}
	} else {
		fmt.Printf("❌ 视频上传失败: %s - %s\n", response.GetRetCode(), response.GetRetMsg())
	}

	return nil
}

// uploadPdfExample PDF上传示例
func uploadPdfExample(fileService *services.FileService) error {
	// 获取示例PDF文件路径
	filePath, err := getExampleFilePath("test_document.pdf")
	if err != nil {
		fmt.Printf("提示: %v\n", err)
		fmt.Println("支持的文档格式: .pdf")
		return nil // 不返回错误，只是提示
	}

	fmt.Printf("使用PDF文件: %s\n", filePath)

	// 打印文件信息
	printFileInfo(filePath)

	// 创建PDF上传请求
	request := &models.PdfUploadRequest{}

	// 设置文件路径
	fmt.Println("🔧 正在设置文件路径...")
	if err := request.SetFileFromPath(filePath); err != nil {
		return fmt.Errorf("设置文件路径失败: %w", err)
	}

	// 打印请求信息
	printRequestInfo(request)

	// 发送上传请求
	fmt.Println("📤 正在发送上传请求...")
	response, err := fileService.UploadPdf(request)
	if err != nil {
		fmt.Printf("❌ 请求发送失败: %v\n", err)
		return fmt.Errorf("上传PDF失败: %w", err)
	}

	// 打印响应信息
	printResponseInfo("PDF上传", response)

	// 处理响应
	if response.IsSuccess() {
		fmt.Printf("✅ PDF上传成功！\n")
		if response.GetFileURL() != "" {
			fmt.Printf("  文件URL: %s\n", response.GetFileURL())
		}
		if response.GetMediaID() != "" {
			fmt.Printf("  媒体ID: %s\n", response.GetMediaID())
		}
	} else {
		fmt.Printf("❌ PDF上传失败: %s - %s\n", response.GetRetCode(), response.GetRetMsg())
	}

	return nil
}

// sendRequestAndHandleResponse 发送请求并处理响应的通用方法
func sendRequestAndHandleResponse(fileService *services.FileService, request interface{}, operationName string) error {
	var response *models.FileUploadResponse
	var err error

	// 根据请求类型调用不同的服务方法
	switch req := request.(type) {
	case *models.ImageUploadRequest:
		response, err = fileService.UploadImage(req)
	case *models.VideoUploadRequest:
		response, err = fileService.UploadVideo(req)
	case *models.PdfUploadRequest:
		response, err = fileService.UploadPdf(req)
	default:
		return fmt.Errorf("不支持的请求类型: %T", request)
	}

	if err != nil {
		return fmt.Errorf("请求异常: %w", err)
	}

	if response.IsSuccess() {
		fmt.Printf("%s成功！\n", operationName)
		if response.GetMediaID() != "" {
			fmt.Printf("媒体文件ID: %s\n", response.GetMediaID())
		}
		if response.GetFileURL() != "" {
			fmt.Printf("文件URL: %s\n", response.GetFileURL())
		}
	} else {
		fmt.Printf("%s失败: %s - %s\n", operationName, response.GetRetCode(), response.GetRetMsg())
	}

	return nil
}

// printSignatureDebugInfo 打印签名调试信息
func printSignatureDebugInfo() {
	fmt.Println("\n🔍 签名调试信息:")

	// 模拟签名过程
	method := "POST"
	uri := "/base/file/upload/image"
	timestamp := "1748002534"
	nonce := "9387290fdf5a8716432a6ba2b073cbe1"
	meta := `{"abstract":"IrpvIYWny60Y5w6jjPp1LRzxH3nT4PBBDV43vXlQPRc=","alg":"SM3","filename":"test_image.png"}`

	// 构造签名字符串
	signStr := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n", method, uri, timestamp, nonce, meta)

	fmt.Printf("签名字符串构造:\n")
	fmt.Printf("  Method: %s\n", method)
	fmt.Printf("  URI: %s\n", uri)
	fmt.Printf("  Timestamp: %s\n", timestamp)
	fmt.Printf("  Nonce: %s\n", nonce)
	fmt.Printf("  Body: %s\n", meta)
	fmt.Printf("完整签名字符串:\n%s", signStr)
	fmt.Printf("签名字符串长度: %d\n", len(signStr))
	fmt.Printf("签名字符串十六进制: %x\n", []byte(signStr))

	// 尝试手动签名
	fmt.Println("\n🔧 尝试手动签名:")
	signBytes, err := utils.SM2Sign([]byte(signStr), sm2PrivateKey)
	if err != nil {
		fmt.Printf("❌ 手动签名失败: %v\n", err)
	} else {
		signature := utils.ToBase64String(signBytes)
		fmt.Printf("✅ 手动签名成功: %s\n", signature)
	}
}
